<?php

namespace ly;

/**
 * @method static bool int(string $value, null|string $zero = null) 整数（$zero表示与0比较符号，例：<、<=、>、>=）
 * @method static bool decimal(string $value, null|string $zero = null, null|int $digit = null) 小数（$zero表示与0比较符号，例：<、<=、>、>=；$digit表示小数最大位数）
 * @method static bool money(string $value, null|string $zero = null) 金钱（$zero表示与0比较符号，例：<、<=、>、>=）
 * @method static bool date(string $value, string $separator = '-') 年-月-日
 * @method static bool datetime(string $value, string $separator = '-', string $separator2 = ':') 年-月-日 时:分:秒
 * @method static bool email(string $value) 邮箱
 * @method static bool mobile(string $value, bool $strict = true) 手机号
 * @method static bool lrc(string $value) lrc歌词
 * @method static bool md5(string $value, null|bool $upper = null) md5
 * @method static bool number(string $value) 数字
 * @method static bool alpha(string $value, null|bool $upper = null) 英文字母
 * @method static bool alnum(string $value, null|bool $upper = null) 英文字母+数字
 * @method static bool chinese(string $value, bool $include = false) 中文
 * @method static bool video(string $value, bool $dot = true) 视频
 * @method static bool audio(string $value, bool $dot = true) 音频
 * @method static bool image(string $value, bool $dot = true) 图片
 * @method static bool compress(string $value, bool $dot = true) 压缩包
 */
class Regex {

	public static function __callStatic ($name, $args) {
		$regex = [
			'int'      => function ($zero = null) {
				return self::_decimal($zero, 0);
			},
			'decimal'  => function ($zero = null, $digit = null) {
				return self::_decimal($zero, $digit);
			},
			'money'    => function ($zero = null) {
				return self::_decimal($zero, 2);
			},
			'date'     => function ($separator = '-') {
				$separator = preg_quote($separator, '/');

				return "/^[1-9]\d{3}{$separator}(0[1-9]|1[0-2]){$separator}(0[1-9]|[1-2][0-9]|3[0-1])$/";
			},
			'datetime' => function ($separator = '-', $separator2 = ':') {
				$separator  = preg_quote($separator, '/');
				$separator2 = preg_quote($separator2, '/');

				return "/^[1-9]\d{3}{$separator}(0[1-9]|1[0-2]){$separator}(0[1-9]|[1-2][0-9]|3[0-1])\s+(2[0-3]|[0-1]\d){$separator2}[0-5]\d{$separator2}[0-5]\d$/";
			},
			'email'    => '/^(\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*)$/',
			'mobile'   => function ($strict = true) {
				return $strict === null || $strict ? '/^1(([38]\d)|(4[14-9])|([59][0-35-9])|6[25-7]|(7[0-8]))\d{8}$/' : '/^1[3-9]\d{9}$/';
			},
			'lrc'      => '/(^|\n)(\[(\d+:)?[0-5]\d:[0-5]\d(\.\d+)?\])+/',
			'md5'      => function ($upper = null) {
				return is_bool($upper) ? $upper ? '/^[0-9A-F]{32}$/' : '/^[0-9a-f]{32}$/' : '/^([0-9a-f]{32}|[0-9A-F]{32})$/';
			},
			'number'   => function () {
				return self::_decimal('>=', 0);
			},
			'alpha'    => function ($upper = null) {
				return is_bool($upper) ? $upper ? '/^[A-Z]+$/' : '/^[a-z]+$/' : '/^[a-zA-Z]+$/';
			},
			'alnum'    => function ($upper = null) {
				return is_bool($upper) ? $upper ? '/^[0-9A-Z]+$/' : '/^[0-9a-z]+$/' : '/^[0-9a-zA-Z]+$/';
			},
			'chinese'  => function ($include = false) {
				return $include ? '/[\x{4e00}-\x{9fa5}]+/u' : '/^[\x{4e00}-\x{9fa5}]+$/u';
			},

			'video'    => function ($dot = true) {
				return self::_extension("3gp|avi|asf|dat|mp4|f[4l]v|swf|m[24klo]v|m2ts?|ogv|rm(vb)?|ram|wmv|mp(eg?|g)|qt|vob", $dot);
			},
			'audio'    => function ($dot = true) {
				return self::_extension("mp3|m4a|m4r|mid|aac|ape|wma|wav|ogg|flac|dsf|dsd|dff|amr|mpa|ram|ra|aif", $dot);
			},
			'image'    => function ($dot = true) {
				return self::_extension("jpg|jpeg|png|icon|gif|bmp", $dot);
			},
			'compress' => function ($dot = true) {
				return self::_extension("zipx?|[jrtx]ar|7z|iso|img|isz|cab|arj|ace|alz|uue|gz|gzip|t[agpx]z|bzip2|bz2?|tbz2?|xz|lzh|lha|z|xpi|win|swm|rpm|deb|dmg|hfs|cpio|lzma(86)?|split|001", $dot);
			}
		];

		if (is_array($args)) {
			$val  = @$args[0];
			$args = array_slice($args, 1);
		} else {
			$val  = $args;
			$args = [];
		}
		if ($val === null || !array_key_exists($name, $regex)) return false;

		$re = $regex[$name];
		if (is_callable($re)) $re = call_user_func($re, ...$args);

		return boolval(preg_match($re, $val));
	}

	private static function _decimal ($zero = null, $digit = null) {
		$dot = is_numeric($digit) ? $digit > 0 ? "(\.\d{1,{$digit}})" : '' : "(\.\d+)";
		switch ($zero) {
			case '<':
				return "/^-[1-9]\d*{$dot}?$/";
			case '<=':
				return "/^(0|-[1-9]\d*){$dot}?$/";
			case '>':
				return "/^[1-9]\d*{$dot}?$/";
			case '>=':
				return "/^(0|[1-9]\d*){$dot}?$/";
			default:
				return "/^(0|-?[1-9]\d*){$dot}?$/";
		}
	}

	private static function _extension ($extensions, $dot = true) {
		$dot = $dot === null || $dot ? '\.' : '^';

		return "/{$dot}({$extensions})$/i";
	}
}